#include "drv_l1_adc.h"
#include "application.h"
//160 * 1024 -> 5minutes 
// it can modify record time
#define IndexBuffer_Size			(320 * 1024)//(640 * 1024)//(640 * 1024)//(160 * 1024)			// Do not modify this
#define AVI_FILE_MAX_RECORD_SIZE	(1001 * 1024 * 1024)	// 2GB

/* global varaible */
AviEncPara_t			AviEncPara;
AviEncPara_t			*pAviEncPara = &AviEncPara;
AviEncAudPara_t			AviEncAudPara;
AviEncAudPara_t			*pAviEncAudPara = &AviEncAudPara;
AviEncPacker_t			AviEncPacker0;
AviEncPacker_t			*pAviEncPacker0 = &AviEncPacker0;
AviEncPacker_t			AviEncPacker1;
AviEncPacker_t			*pAviEncPacker1 = &AviEncPacker1;

GP_AVI_AVISTREAMHEADER	avi_aud_stream_header;
GP_AVI_AVISTREAMHEADER	avi_vid_stream_header;
GP_AVI_BITMAPINFO		avi_bitmap_info;
GP_AVI_PCMWAVEFORMAT	avi_wave_info;
 
static DMA_STRUCT		g_avi_adc_dma_dbf;
static INT8U			g_pcm_index;

void (*pfn_avi_encode_put_data) (void *WorkMem, AVIPACKER_FRAME_INFO *pFrameInfo);

/****************************************************************************/
AviEncVidPara_t AviEncVidPara;
AviEncVidPara_t *pAviEncVidPara = &AviEncVidPara;

void avi_encode_end(void *workmem)
{
	//=======================================================================
	//		avi encode end,
	// ISRC: source; IART: Artist; ICOP: copyright; IARL: achival location
	// ICMS: commissioned; ICMT: comments;  ICRD: create date; ICRP: cropped
	// IDIM: dimensions; IDPI: dots per inch; IENG: engineer; IGNR: genre
	// IKEY: keyword; ILGT: lightness; IMED: medium; INAM: name;
	// IPLT: palette setting; IPRD: product; ISFT: software; ISHP: sharpness
	// ISRC: source; ISRF: source form; ITCH: technician
	//=======================================================================

	//add description to avi file
	AviPackerV3_AddInfoStr(workmem, "ISRC", "Generplus");
	AviPackerV3_AddInfoStr(workmem, "IART", "Generplus");
	AviPackerV3_AddInfoStr(workmem, "ICOP", "Generplus");
	AviPackerV3_AddInfoStr(workmem, "ICRD", "2010-06-29");
}

/****************************************************************************/

/*
 *	AviPacker_mem_alloc
 */
static INT32S AviPacker_mem_alloc(AviEncPacker_t *pAviEncPacker)
{
	INT32S	nRet;

	pAviEncPacker->index_buffer_size = IndexBuffer_Size;
	if(!pAviEncPacker->index_write_buffer)
	{
		pAviEncPacker->index_write_buffer = (INT32U *) gp_malloc_align(IndexBuffer_Size, 32);
	}

	if(!pAviEncPacker->index_write_buffer)
	{
		RETURN(STATUS_FAIL);
	}

	pAviEncPacker->avi_workmem = (void *) gp_malloc_align(AviPackerV3_GetWorkMemSize(), 32);
	if(!pAviEncPacker->avi_workmem)
	{
		RETURN(STATUS_FAIL);
	}

#if GPS_AVI_WRITE && (GPS_TYPE == END_OF_FILE)
	pAviEncPacker->gps_buf_size = GPS_BUF_SIZE;
	pAviEncPacker->gps_buf_used = 0;
	pAviEncPacker->gps_buf = (void *) gp_malloc_align(pAviEncPacker->gps_buf_size, 32);
	if(!pAviEncPacker->gps_buf)
	{
		if(pAviEncPacker == pAviEncPacker0)
		{
			DBG_PRINT("Alloc front gps_buf fail\r\n");
		}
		else
		{
			DBG_PRINT("Alloc rear gps_buf fail\r\n");
		}
		RETURN(STATUS_FAIL);
	}
	else
	{
		if(pAviEncPacker == pAviEncPacker0)
		{
			DBG_PRINT("Alloc front gps_buf addr=0x%x, size=%d\r\n", pAviEncPacker->gps_buf, pAviEncPacker->gps_buf_size);
		}
		else
		{
			DBG_PRINT("Alloc rear gps_buf addr=0x%x, size=%d\r\n", pAviEncPacker->gps_buf, pAviEncPacker->gps_buf_size);
		}
	}
#else
	pAviEncPacker->gps_buf = NULL;
	pAviEncPacker->gps_buf_size = 0;
	pAviEncPacker->gps_buf_used = 0;
#endif

	gp_memset((INT8S *) pAviEncPacker->avi_workmem, 0x00, AviPackerV3_GetWorkMemSize());
	gp_memset((INT8S *) pAviEncPacker->index_write_buffer, 0, pAviEncPacker->index_buffer_size);

#if GPS_AVI_WRITE && (GPS_TYPE == END_OF_FILE)
	gp_memset((INT8S *) pAviEncPacker->gps_buf, 0, pAviEncPacker->gps_buf_size);
#endif
	return STATUS_OK;

Return:
	if(pAviEncPacker->index_write_buffer != NULL)
	{
		gp_free(pAviEncPacker->index_write_buffer);
	}

#if GPS_AVI_WRITE && (GPS_TYPE == END_OF_FILE)
	pAviEncPacker->gps_buf_size = 0;
	if(pAviEncPacker->gps_buf != NULL)
	{
		gp_free(pAviEncPacker->gps_buf);
		pAviEncPacker->gps_buf = 0;
	}
#endif

	return nRet;
}

/****************************************************************************/

/*
 *	avi_encode_init
 */
void avi_encode_init(void)
{
	// Init video task variables
	pAviEncVidPara = &AviEncVidPara;
	gp_memset((INT8S *) pAviEncVidPara, 0, sizeof(AviEncVidPara_t));

	// Init audio task variabls
	pAviEncAudPara = &AviEncAudPara;
	gp_memset((INT8S *) pAviEncAudPara, 0, sizeof(AviEncAudPara_t));

	pAviEncPara = &AviEncPara;
	gp_memset((INT8S *) pAviEncPara, 0, sizeof(AviEncPara_t));
	pAviEncPacker0 = &AviEncPacker0;
	gp_memset((INT8S *) pAviEncPacker0, 0, sizeof(AviEncPacker_t));

	pAviEncPacker1 = &AviEncPacker1;
	gp_memset((INT8S *) pAviEncPacker1, 0, sizeof(AviEncPacker_t));

	pAviEncPacker0->file_handle = -1;
	pAviEncPacker1->file_handle = -1;
}

/****************************************************************************/

/*
 *	avi_encode_set_file_handle_and_caculate_free_size
 */
INT32S avi_encode_set_file_handle_and_caculate_free_size(AviEncPacker_t *pAviEncPacker, INT16S FileHandle, INT16S txt_FileHandle)
{
#if AVI_ENCODE_CAL_DISK_SIZE_EN
	pAviEncPara->disk_free_size = vfsFreeSpace(STORAGE_DEVICE) - 3145728;	//3*1024*1024
	pAviEncPara->record_total_size = 2 * 32 * 1024 + 16;	//avi header + data is 32k align + index header
#endif
	pAviEncPacker->txt_handle = txt_FileHandle;
	pAviEncPacker->file_handle = FileHandle;
	return STATUS_OK;
}

/****************************************************************************/

/*
 *	avi_enc_packer_init
 */
INT32U avi_enc_packer_init(AviEncPacker_t *pAviEncPacker)
{
	INT32S	nRet;

	if(pAviEncPacker == pAviEncPacker0)
	{
		pAviEncPacker->task_prio = PRIORITY_AVI_PACKER0;
	}
	else
	if(pAviEncPacker == pAviEncPacker1)
	{
		pAviEncPacker->task_prio = PRIORITY_AVI_PACKER1;
	}
	else
	{
		RETURN(STATUS_FAIL);
	}

	nRet = AviPackerV3_TaskCreate
		(
			pAviEncPacker->task_prio,
			pAviEncPacker->avi_workmem,
			pAviEncPacker->index_write_buffer,
			pAviEncPacker->index_buffer_size,
			pAviEncPacker->return_queue,
			pAviEncPacker->return_msg,
			pAviEncPacker->print_flag
		);
	if(nRet < 0)
		RETURN(STATUS_FAIL);

	AviPackerV3_SetFlushInterval(pAviEncPacker->avi_workmem, 1);
	AviPackerV3_SetErrHandler(pAviEncPacker->avi_workmem, avi_packer_err_handle);
	nRet = STATUS_OK;
Return:
	return nRet;
}

/****************************************************************************/

/*
 *	avi_enc_packer_start
 */
INT32U avi_enc_packer_start(AviEncPacker_t *pAviEncPacker)
{
	INT32S	nRet;
	INT32U	bflag;

	if(pAviEncPacker == pAviEncPacker0)
	{
		bflag = AVI_ENCODER_STATE_PACKER0;
	}
	else
	if(pAviEncPacker == pAviEncPacker1)
	{
		bflag = AVI_ENCODER_STATE_PACKER1;
	}
	else
	{
		RETURN(STATUS_FAIL);
	}

	//if((avi_encoder_state_get() & bflag) == 0)
	//{
	switch(pAviEncPara->source_type)
	{
	case SOURCE_TYPE_FS:
		avi_encode_set_avi_header(pAviEncPacker);
		nRet = AviPackerV3_Open
			(
				pAviEncPacker->avi_workmem,
				pAviEncPacker->file_handle,
				pAviEncPacker->file_handle_tmp,
				pAviEncPacker->txt_handle,
				pAviEncPacker->p_avi_vid_stream_header,
				pAviEncPacker->bitmap_info_cblen,
				pAviEncPacker->p_avi_bitmap_info,
				pAviEncPacker->p_avi_aud_stream_header,
				pAviEncPacker->wave_info_cblen,
				pAviEncPacker->p_avi_wave_info
			);
		pfn_avi_encode_put_data = AviPackerV3_WriteData;
		break;
	}

	avi_encoder_state_set(bflag);
	DBG_PRINT("a.AviPackerOpen[0x%x] = 0x%x\r\n", bflag, nRet);

	//}
	//else
	//{
	//	RETURN(STATUS_FAIL);
	//}
	nRet = STATUS_OK;

Return:
	return nRet;
}

/****************************************************************************/

/*
 *	avi_enc_start
 */
INT32S avi_enc_start(void)
{
	INT32S	nRet;

	nRet = STATUS_OK;

	if((avi_encode_get_status() & C_AVI_ENCODE_START) == 0)
	{
		POST_MESSAGE(videoEncodeApQ, MSG_AVI_START_ENCODE, videoEncodeMsgAck, 10000);
		avi_encode_set_status(C_AVI_ENCODE_START);
		DBG_PRINT("encode start\r\n");
	}

	// start audio
	if(pAviEncAudPara->audio_format && ((avi_encode_get_status() & C_AVI_ENCODE_AUDIO) == 0))
	{
		if(avi_audio_record_start() < 0)
			RETURN(STATUS_FAIL);
		avi_encode_set_status(C_AVI_ENCODE_AUDIO);
		DBG_PRINT("audio start\r\n");
	}

Return:
	return nRet;
}

/****************************************************************************/

/*
 *	vid_enc_preview_start
 */
INT32S vid_enc_preview_start(void)
{
	INT32S	nRet;

	nRet = STATUS_OK;
#if 0
	if((avi_encoder_state_get() & AVI_ENCODER_STATE_SENSOR) == 0)
	{
		avi_encoder_state_set(AVI_ENCODER_STATE_SENSOR);
		POST_MESSAGE(videoEncodeApQ, MSG_AVI_START_SENSOR, videoEncodeMsgAck, 5000);
	}
#else
	// allow runtime restart sensor
	avi_encoder_state_set(AVI_ENCODER_STATE_SENSOR);
	POST_MESSAGE(videoEncodeApQ, MSG_AVI_START_SENSOR, videoEncodeMsgAck, 1000);
#endif

Return:
	if(nRet < 0)
	{
		DBG_PRINT("wwj: start sensor fail...\r\n");
	}

	return nRet;
}

/****************************************************************************/

/*
 *	vid_enc_preview_stop
 */
INT32S vid_enc_preview_stop(void)
{
	INT32S	nRet;

	nRet = STATUS_OK;

	if(avi_encoder_state_get() & AVI_ENCODER_STATE_SENSOR)
	{
		POST_MESSAGE(videoEncodeApQ, MSG_AVI_STOP_SENSOR, videoEncodeMsgAck, 5000);
		avi_encoder_state_clear(AVI_ENCODER_STATE_SENSOR);
	}

Return:
	return nRet;
}

/****************************************************************************/

/*
 *	avi_enc_stop
 */
INT32S avi_enc_stop(void)
{
	INT32S	nRet;

	nRet = STATUS_OK;

	// stop avi encode
	if(avi_encode_get_status() & C_AVI_ENCODE_START)
	{
		avi_encode_clear_status(C_AVI_ENCODE_START);
		POST_MESSAGE(videoEncodeApQ, MSG_AVI_STOP_ENCODE, videoEncodeMsgAck, 500);
		DBG_PRINT("b.encode stop\r\n");
	}

Return:
	sensor_record_stop_flush();

	// stop audio
	if(avi_encode_get_status() & C_AVI_ENCODE_AUDIO)
	{
		avi_encode_clear_status(C_AVI_ENCODE_AUDIO);
		if(avi_audio_record_stop() < 0)
			return(STATUS_FAIL);
		DBG_PRINT("a.audio stop\r\n");
	}

	return nRet;
}

/****************************************************************************/

/*
 *	avi_enc_packer_stop
 */
INT32U avi_enc_packer_stop(AviEncPacker_t *pAviEncPacker, INT8U continue_flag)
{
	INT32S	nRet;
	INT32U	bflag;

	if(pAviEncPacker == pAviEncPacker0)
	{
		bflag = AVI_ENCODER_STATE_PACKER0;
	}
	else
	if(pAviEncPacker == pAviEncPacker1)
	{
		bflag = AVI_ENCODER_STATE_PACKER1;
	}
	else
	{
		RETURN(STATUS_FAIL);
	}

	//if(avi_encoder_state_get() & bflag)
	//{
	switch(pAviEncPara->source_type)
	{
	case SOURCE_TYPE_FS:
		avi_encode_end(pAviEncPacker->avi_workmem);

#if GPS_AVI_WRITE && (GPS_TYPE == END_OF_FILE)
		nRet = AviPackerV3_Close(pAviEncPacker->avi_workmem, pAviEncPacker->gps_buf, pAviEncPacker->gps_buf_used, continue_flag);
		pAviEncPacker->gps_buf_used = 0;
#else
		nRet = AviPackerV3_Close(pAviEncPacker->avi_workmem, NULL, 0, continue_flag);
#endif

		avi_encode_close_file(pAviEncPacker);
		break;
	}

	if(nRet < 0)
		RETURN(STATUS_FAIL);
	if(!continue_flag)
		avi_encoder_state_clear(bflag);
	DBG_PRINT("c.AviPackerClose[0x%x] = 0x%x\r\n", bflag, nRet);

	//}
	nRet = STATUS_OK;

Return:
	return nRet;
}

/****************************************************************************/
/*
 *	avi_enc_packer_fast_stop_and_start
 */
/*
INT32U avi_enc_packer_switch_file(AviEncPacker_t *pAviEncPacker, INT16S fd_new, INT16S fd_txt_new)
{
	INT32S nRet;
	INT32U bflag;

	if(pAviEncPacker == pAviEncPacker0)
	{
		bflag = AVI_ENCODER_STATE_PACKER0;
	}
	else if(pAviEncPacker == pAviEncPacker1)
	{
		bflag = AVI_ENCODER_STATE_PACKER1;
	}
	else
	{
		RETURN(STATUS_FAIL);
	}

	if(avi_encoder_state_get() & bflag)
	{
		switch(pAviEncPara->source_type)
		{
		case SOURCE_TYPE_FS:
			avi_encode_end(pAviEncPacker->avi_workmem);
			nRet = AviPackerV3_SwitchFile(pAviEncPacker->avi_workmem,
									&pAviEncPacker->file_handle,
									&pAviEncPacker->txt_handle,
									pAviEncPacker->p_avi_vid_stream_header,
									pAviEncPacker->bitmap_info_cblen,
									pAviEncPacker->p_avi_bitmap_info,
									pAviEncPacker->p_avi_aud_stream_header,
									pAviEncPacker->wave_info_cblen,
									pAviEncPacker->p_avi_wave_info,
									fd_new,
									fd_txt_new);
			break;
		}

		if(nRet < 0) RETURN(STATUS_FAIL);
		DBG_PRINT("c.AviPackerSwitch[0x%x] = 0x%x\r\n", bflag, nRet);
	} else {
		RETURN(STATUS_FAIL);
	}
	nRet = STATUS_OK;
Return:
	return nRet;
}
*/
/****************************************************************************/

/*
 *	avi_enc_save_jpeg
 */
INT32U  Get_Jpeg_buffer_Size=0;
INT32S avi_enc_save_jpeg(void)
{
 	Get_Jpeg_buffer_Size = DEBUG_CAPTURE_PHOTO_JPEG_SIZE;
#if C_SENSOR_SAVE_RAW_DATA	
	OSQPost(videoEncodeApQ, (void *) MSG_AVI_CAPTURE_RAW_DATA);
#else
    OSQPost(videoEncodeApQ, (void *) MSG_AVI_CAPTURE_PICTURE);
#endif
	return STATUS_OK;
}

/****************************************************************************/

/*
 *	vid_enc_preview_buf_to_dummy
 */
INT32S vid_enc_preview_buf_to_dummy(void)
{
	INT32S	nRet;

	nRet = STATUS_OK;

	POST_MESSAGE(videoEncodeApQ, MSG_PREVIEW_BUF_TO_DUMMY, videoEncodeMsgAck, 100);
Return:
	return nRet;
}

/****************************************************************************/

/*
 *	vid_enc_preview_buf_to_display
 */
INT32S vid_enc_preview_buf_to_display(INT32U mode)
{
	INT32S	nRet = STATUS_OK;

	//debug
	if(mode >= PREVIEW_MODE_VALID)
	{
		do
		{
			DBG_PRINT("[ERROR] invalid preview mode=%d\r\n, @%s:%d\r\n", mode, __func__, __LINE__);
		}
		while(0);
		mode = PREVIEW_MODE_FRONT;
	}

	POST_MESSAGE(videoEncodeApQ, MSG_PREVIEW_BUF_TO_DISPLAY | mode, videoEncodeMsgAck, 100);
Return:
	return nRet;
}

// file handle
INT16S avi_encode_close_file(AviEncPacker_t *pAviEncPacker)
{
	INT32S	nRet;

	nRet = close(pAviEncPacker->file_handle);
    #if GPS_TXT
	nRet |= close(pAviEncPacker->txt_handle);
    #endif
	pAviEncPacker->file_handle = -1;
    #if GPS_TXT
	pAviEncPacker->txt_handle = -1;
    #endif
	return nRet;
}

INT32S avi_encode_set_avi_header(AviEncPacker_t *pAviEncPacker)
{
	INT16U	sample_per_block, package_size;

	//INT8U	temp[6] = { 0, 1, 2, 3, 5, 6 };
	INT8U	temp[6] = { 20, 3, 5, 10, 5, 10 };
	pAviEncPacker->p_avi_aud_stream_header = &avi_aud_stream_header;
	pAviEncPacker->p_avi_vid_stream_header = &avi_vid_stream_header;
	pAviEncPacker->p_avi_bitmap_info = &avi_bitmap_info;
	pAviEncPacker->p_avi_wave_info = &avi_wave_info;
	gp_memset((INT8S *) pAviEncPacker->p_avi_aud_stream_header, 0, sizeof(GP_AVI_AVISTREAMHEADER));
	gp_memset((INT8S *) pAviEncPacker->p_avi_vid_stream_header, 0, sizeof(GP_AVI_AVISTREAMHEADER));
	gp_memset((INT8S *) pAviEncPacker->p_avi_bitmap_info, 0, sizeof(GP_AVI_BITMAPINFO));
	gp_memset((INT8S *) pAviEncPacker->p_avi_wave_info, 0, sizeof(GP_AVI_PCMWAVEFORMAT));

	//audio
	avi_aud_stream_header.fccType[0] = 'a';
	avi_aud_stream_header.fccType[1] = 'u';
	avi_aud_stream_header.fccType[2] = 'd';
	avi_aud_stream_header.fccType[3] = 's';

	switch(pAviEncAudPara->audio_format)
	{
	case WAVE_FORMAT_PCM:
		pAviEncPacker->wave_info_cblen = 16;
		avi_aud_stream_header.fccHandler[0] = 1;
		avi_aud_stream_header.fccHandler[1] = 0;
		avi_aud_stream_header.fccHandler[2] = 0;
		avi_aud_stream_header.fccHandler[3] = 0;

		avi_wave_info.wFormatTag = WAVE_FORMAT_PCM;
		avi_wave_info.nChannels = pAviEncAudPara->channel_no;
		avi_wave_info.nSamplesPerSec = pAviEncAudPara->audio_sample_rate;
		avi_wave_info.nAvgBytesPerSec = pAviEncAudPara->channel_no * pAviEncAudPara->audio_sample_rate * 2;
		avi_wave_info.nBlockAlign = pAviEncAudPara->channel_no * 2;
		avi_wave_info.wBitsPerSample = 16;	//16bit
		avi_aud_stream_header.dwScale = avi_wave_info.nBlockAlign;
		avi_aud_stream_header.dwRate = avi_wave_info.nAvgBytesPerSec;
		avi_aud_stream_header.dwSampleSize = avi_wave_info.nBlockAlign;;
		break;

	case WAVE_FORMAT_ADPCM:
		pAviEncPacker->wave_info_cblen = 50;
		avi_aud_stream_header.fccHandler[0] = 0;
		avi_aud_stream_header.fccHandler[1] = 0;
		avi_aud_stream_header.fccHandler[2] = 0;
		avi_aud_stream_header.fccHandler[3] = 0;

		package_size = 0x100;
		if(pAviEncAudPara->channel_no == 1)
			sample_per_block = 2 * package_size - 12;
		else
		if(pAviEncAudPara->channel_no == 2)
			sample_per_block = package_size - 12;
		else
			sample_per_block = 1;

		avi_wave_info.wFormatTag = WAVE_FORMAT_ADPCM;
		avi_wave_info.nChannels = pAviEncAudPara->channel_no;
		avi_wave_info.nSamplesPerSec = pAviEncAudPara->audio_sample_rate;
		avi_wave_info.nAvgBytesPerSec = package_size * pAviEncAudPara->audio_sample_rate / sample_per_block;	// = PackageSize * FrameSize / fs
		avi_wave_info.nBlockAlign = package_size;	//PackageSize
		avi_wave_info.wBitsPerSample = 4;			// 4bit
		avi_wave_info.cbSize = 32;

		// extension ...
		avi_wave_info.ExtInfo[0] = 0x01F4;
		avi_wave_info.ExtInfo[1] = 0x0007;
		avi_wave_info.ExtInfo[2] = 0x0100;
		avi_wave_info.ExtInfo[3] = 0x0000;
		avi_wave_info.ExtInfo[4] = 0x0200;
		avi_wave_info.ExtInfo[5] = 0xFF00;
		avi_wave_info.ExtInfo[6] = 0x0000;
		avi_wave_info.ExtInfo[7] = 0x0000;

		avi_wave_info.ExtInfo[8] = 0x00C0;
		avi_wave_info.ExtInfo[9] = 0x0040;
		avi_wave_info.ExtInfo[10] = 0x00F0;
		avi_wave_info.ExtInfo[11] = 0x0000;
		avi_wave_info.ExtInfo[12] = 0x01CC;
		avi_wave_info.ExtInfo[13] = 0xFF30;
		avi_wave_info.ExtInfo[14] = 0x0188;
		avi_wave_info.ExtInfo[15] = 0xFF18;
		break;

	case WAVE_FORMAT_IMA_ADPCM:
		pAviEncPacker->wave_info_cblen = 20;
		avi_aud_stream_header.fccHandler[0] = 0;
		avi_aud_stream_header.fccHandler[1] = 0;
		avi_aud_stream_header.fccHandler[2] = 0;
		avi_aud_stream_header.fccHandler[3] = 0;

		package_size = 0x100;
		if(pAviEncAudPara->channel_no == 1)
			sample_per_block = 2 * package_size - 7;
		else
		if(pAviEncAudPara->channel_no == 2)
			sample_per_block = package_size - 7;
		else
			sample_per_block = 1;

		avi_wave_info.wFormatTag = WAVE_FORMAT_IMA_ADPCM;
		avi_wave_info.nChannels = pAviEncAudPara->channel_no;
		avi_wave_info.nSamplesPerSec = pAviEncAudPara->audio_sample_rate;
		avi_wave_info.nAvgBytesPerSec = package_size * pAviEncAudPara->audio_sample_rate / sample_per_block;
		avi_wave_info.nBlockAlign = package_size;	//PackageSize
		avi_wave_info.wBitsPerSample = 4;			// 4bit
		avi_wave_info.cbSize = 2;

		// extension ...
		avi_wave_info.ExtInfo[0] = sample_per_block;
		break;

	default:
		pAviEncPacker->wave_info_cblen = 0;
		pAviEncPacker->p_avi_aud_stream_header = NULL;
		pAviEncPacker->p_avi_wave_info = NULL;
	}

	avi_aud_stream_header.dwScale = avi_wave_info.nBlockAlign;
	avi_aud_stream_header.dwRate = avi_wave_info.nAvgBytesPerSec;
	avi_aud_stream_header.dwSampleSize = avi_wave_info.nBlockAlign;
	avi_aud_stream_header.dwLength =  temp[ap_state_config_record_time_get()]*60*AUD_REC_SAMPLING_RATE;

	//video
	avi_vid_stream_header.fccType[0] = 'v';
	avi_vid_stream_header.fccType[1] = 'i';
	avi_vid_stream_header.fccType[2] = 'd';
	avi_vid_stream_header.fccType[3] = 's';

	avi_vid_stream_header.dwScale = pAviEncVidPara->dwScale;
	if(pAviEncPacker->front_or_rear == 0)
	{	//front
		avi_vid_stream_header.dwRate = pAviEncVidPara->dwRate;
		avi_vid_stream_header.rcFrame.right = pAviEncVidPara->encode_width;
		avi_vid_stream_header.rcFrame.bottom = pAviEncVidPara->encode_height;
		avi_vid_stream_header.dwLength =  temp[ap_state_config_record_time_get()]*60*pAviEncVidPara->dwRate;
		avi_vid_stream_header.dwSuggestedBufferSize = JPEG_FRONT_OUTPUT_BUFFER_SIZE;
		DBG_PRINT("front_or_rear = front\r\n");
	}
	else
	{	//rear
		avi_vid_stream_header.dwRate = pAviEncVidPara->dwRate_r;
		avi_vid_stream_header.rcFrame.right = pAviEncVidPara->encode_width_r;
		avi_vid_stream_header.rcFrame.bottom = pAviEncVidPara->encode_height_r;
		avi_vid_stream_header.dwLength =  temp[ap_state_config_record_time_get()]*60*pAviEncVidPara->dwRate_r;
		avi_vid_stream_header.dwSuggestedBufferSize = JPEG_REAR_OUTPUT_BUFFER_SIZE;
		DBG_PRINT("front_or_rear = rear\r\n");
	}

	avi_vid_stream_header.fccHandler[0] = 'm';
	avi_vid_stream_header.fccHandler[1] = 'j';
	avi_vid_stream_header.fccHandler[2] = 'p';
	avi_vid_stream_header.fccHandler[3] = 'g';

	avi_bitmap_info.biSize = pAviEncPacker->bitmap_info_cblen = 40;
	if(pAviEncPacker->front_or_rear == 0)
	{	//front
		avi_bitmap_info.biWidth = pAviEncVidPara->encode_width;
		avi_bitmap_info.biHeight = pAviEncVidPara->encode_height;
	}
	else
	{	//rear
		avi_bitmap_info.biWidth = pAviEncVidPara->encode_width_r;
		avi_bitmap_info.biHeight = pAviEncVidPara->encode_height_r;
	}

	avi_bitmap_info.biBitCount = 24;
	avi_bitmap_info.biCompression[0] = 'M';
	avi_bitmap_info.biCompression[1] = 'J';
	avi_bitmap_info.biCompression[2] = 'P';
	avi_bitmap_info.biCompression[3] = 'G';

	if(pAviEncPacker->front_or_rear == 0)
	{	//front
		avi_bitmap_info.biSizeImage = pAviEncVidPara->encode_width * pAviEncVidPara->encode_height * 3;
	}
	else
	{
		avi_bitmap_info.biSizeImage = pAviEncVidPara->encode_width_r * pAviEncVidPara->encode_height_r * 3;
	}

	return STATUS_OK;
}

// status
void avi_encode_set_status(INT32U bit)
{
	pAviEncPara->avi_encode_status |= bit;
}

void avi_encode_clear_status(INT32U bit)
{
	pAviEncPara->avi_encode_status &= ~bit;
}

INT32S avi_encode_get_status(void)
{
	return pAviEncPara->avi_encode_status;
}

INT32S avi_encode_packer_memory_alloc(void)
{
	INT32S	nRet;

	if(AviPacker_mem_alloc(pAviEncPacker0) < 0)
		RETURN(STATUS_FAIL);
	if(AviPacker_mem_alloc(pAviEncPacker1) < 0)
		RETURN(STATUS_FAIL);
	nRet = STATUS_OK;
Return:
	return nRet;
}

// check disk free size
INT32S avi_encode_disk_size_is_enough(INT32S cb_write_size)
{
	INT32S	nRet;

#if AVI_ENCODE_CAL_DISK_SIZE_EN
	INT32U	temp;
	INT64U	disk_free_size;

	temp = pAviEncPara->record_total_size;
	disk_free_size = pAviEncPara->disk_free_size;
	temp += cb_write_size;
	if(temp >= AVI_FILE_MAX_RECORD_SIZE)
		RETURN(2);
	if(temp >= disk_free_size)
		RETURN(FALSE);
	pAviEncPara->record_total_size = temp;
#endif
	nRet = TRUE;

	return nRet;
}

//audio
INT32S avi_audio_memory_allocate(INT32U cblen)
{
	INT32U	i, ptr;

	g_pcm_index = 0;

	cblen = (cblen + 0xF) &~0xF;
	ptr = (INT32U) gp_malloc_align(cblen * AVI_ENCODE_PCM_BUFFER_NO, 16);
	if(!ptr)
	{
		for(i = 0; i < AVI_ENCODE_PCM_BUFFER_NO; i++)
		{
			pAviEncAudPara->pcm_input_addr[i] = 0;
		}

		return STATUS_FAIL;
	}

	for(i = 0; i < AVI_ENCODE_PCM_BUFFER_NO; i++)
	{
		pAviEncAudPara->pcm_input_addr[i] = ptr;
		ptr += cblen;
	}

	return STATUS_OK;
}

void avi_audio_memory_free(void)
{
	INT32U	i;

	if(pAviEncAudPara->pcm_input_addr[0])
	{
		gp_free((void *) pAviEncAudPara->pcm_input_addr[0]);
	}

	for(i = 0; i < AVI_ENCODE_PCM_BUFFER_NO; i++)
	{
		pAviEncAudPara->pcm_input_addr[i] = 0;
	}
}

INT32U avi_audio_get_next_buffer(void)
{
	INT32U	addr;

	addr = pAviEncAudPara->pcm_input_addr[g_pcm_index++];
	if(g_pcm_index >= AVI_ENCODE_PCM_BUFFER_NO)
		g_pcm_index = 0;

	return addr;
}

INT32S avi_adc_double_buffer_put(INT16U *data, INT32U cwlen, OS_EVENT *os_q)
{
	INT32S	status;

	g_avi_adc_dma_dbf.s_addr = (INT32U) P_I2SRX_DATA;
	g_avi_adc_dma_dbf.t_addr = (INT32U) data;
	g_avi_adc_dma_dbf.width = DMA_DATA_WIDTH_4BYTE;
	g_avi_adc_dma_dbf.count = (INT32U) cwlen / 2;
	g_avi_adc_dma_dbf.notify = NULL;
	g_avi_adc_dma_dbf.timeout = 0;

	status = drv_l1_dma_transfer_with_double_buf(&g_avi_adc_dma_dbf, os_q);
	if(status < 0)
		return status;
	return STATUS_OK;
}

INT32U avi_adc_double_buffer_set(INT16U *data, INT32U cwlen)
{
	INT32S	status;

	g_avi_adc_dma_dbf.s_addr = (INT32U) P_I2SRX_DATA;
	g_avi_adc_dma_dbf.t_addr = (INT32U) data;
	g_avi_adc_dma_dbf.width = DMA_DATA_WIDTH_4BYTE;
	g_avi_adc_dma_dbf.count = (INT32U) cwlen / 2;
	g_avi_adc_dma_dbf.notify = NULL;
	g_avi_adc_dma_dbf.timeout = 0;

	status = drv_l1_dma_transfer_double_buf_set(&g_avi_adc_dma_dbf);
	if(status < 0)
		return status;
	return STATUS_OK;
}

INT32S avi_adc_dma_status_get(void)
{
	if(g_avi_adc_dma_dbf.channel == 0xff)
		return -1;

	return drv_l1_dma_status_get(g_avi_adc_dma_dbf.channel);
}

void avi_adc_double_buffer_free(void)
{
	drv_l1_dma_transfer_double_buf_free(&g_avi_adc_dma_dbf);
	g_avi_adc_dma_dbf.channel = 0xff;
}

void avi_adc_hw_start(INT16U sampling_rate)
{
	i2s_rx_init(0);
	i2s_rx_sample_rate_set(sampling_rate);
	i2s_rx_mono_ch_set();
	i2s_rx_start();
}

void avi_adc_hw_stop(void)
{
	i2s_rx_stop(0);
}
